package com.ruoyi.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.ruoyi.config.WxPayConfig;
import com.ruoyi.enums.WxAppApi;
import com.ruoyi.service.WxAppService;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class WxAppServiceImpl implements WxAppService {
    @Value("${wxapp.api-token-path}")
    private String TOKEN_PATH;

    @Value("${wxapp.app-token-file-name}")
    private String TOKEN_FILE_NAME;

    @Resource
    private WxPayConfig wxPayConfig;

    @Override
    public Map<String, String> getAccessToken() {
        HashMap<String, String> result = new HashMap<>();
        String url = wxPayConfig.getAppDomain() + WxAppApi.GET_ACCESS_TOKEN.getUrl()  +
                "?" +
                "grant_type=client_credential" +
                "&appid=" + wxPayConfig.getAppid() +
                "&secret=" + wxPayConfig.getAppSecret();
        System.out.println("请求token的url ===> " + url);
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();
        try (Response response = client.newCall(request).execute()){
            if (response.isSuccessful()) {
                String responseBody = response.body().string();
                final JSONObject jsonObject = JSONObject.parseObject(responseBody);
                if(response.code() == 200) {
                    result.put("success", String.valueOf(response.code()));
                    result.put("access_token", (String) jsonObject.get("access_token"));
                } else {
                    result.put("error", String.valueOf(response.code()));
                    result.put("error_message", (String) jsonObject.get("errormsg"));
                }
            } else {
                result.put("error", "获取token失败");
            }
        }catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return result;
    }

    /**
     * 微信小程序发货
     * @param orderNo 订单编号
     * @param openId 微信的openid
     * @return
     */
    @Override
    public Map<String, String> deliverGoods(String orderNo, String openId) {
        Map<String, String> result = new HashMap<>();
        String tokenFromFile = getTokenFromFile();
        if(tokenFromFile.equals("error")) {
            result.put("error", "获取文件中的token失败");
            return result;
        }
        String url = wxPayConfig.getAppDomain() + WxAppApi.DELIVER_GOODS.getUrl()  +
                "?" +
                "access_token=" + tokenFromFile;
        OkHttpClient okHttpClient = new OkHttpClient();
        // 构建请求参数
        Map<String, Object> formBody = new HashMap<>();

        // order_key 的参数  (订单，需要上传物流信息的订单)
        HashMap<String, Object> orderKey = new HashMap<>();
        orderKey.put("order_number_type", 1); // 订单单号类型 枚举值1，使用下单商户号和商户侧单号；枚举值2，使用微信支付单号。
        orderKey.put("mchid", "1678248340"); // 支付下单商户的商户号，由微信支付生成并下发。
        orderKey.put("out_trade_no", orderNo); // 商户系统内部订单号，只能是数字、大小写字母`_-*`且在同一个商户号下唯一
        formBody.put("order_key", orderKey);

        /**
         * 物流模式，发货方式枚举值：
         * 1、实体物流配送采用快递公司进行实体物流配送形式
         * 2、同城配送
         * 3、虚拟商品，虚拟商品，例如话费充值，点卡等，无实体配送形式
         * 4、用户自提
         */
        formBody.put("logistics_type", 4);

        /**
         * 发货模式，发货模式枚举值：
         * 1、UNIFIED_DELIVERY（统一发货）
         * 2、SPLIT_DELIVERY（分拆发货） 示例值: UNIFIED_DELIVERY
         */
        formBody.put("delivery_mode", 1);

        /**
         * 物流信息列表，发货物流单列表，
         * 支持统一发货（单个物流单）和分拆发货（多个物流单）两种模式，多重性: [1, 10]
         */
        ArrayList<HashMap<String, String>> shippingList = new ArrayList<>();
        HashMap<String, String> shippingMap = new HashMap<>();
        shippingMap.put("item_desc", "商品信息"); // 商品信息
        shippingList.add(shippingMap);
        formBody.put("shipping_list", shippingList);

        // 上传时间
        // 获取当前日期时间，带有时区信息
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
        String formattedDateTime = zonedDateTime.format(formatter);
        formBody.put("upload_time", formattedDateTime);
        /**
         * 支付者，支付者信息
         */
        HashMap<String, String> payer = new HashMap<>();
        payer.put("openid", openId); // 支付者 Openid
        formBody.put("payer", payer);

        String bodyJson = JSONObject.toJSONString(formBody);
        RequestBody body = RequestBody.create(MediaType.parse("application/json"), bodyJson);
        Request post = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        try {
            Response response = okHttpClient.newCall(post).execute();
            if(response.isSuccessful()) {
                String responseBody = response.body().string();
                final JSONObject jsonObject = JSONObject.parseObject(responseBody);
                result = JSONObject.parseObject(responseBody, Map.class);
            } else {
                result.put("error", "向微信发送请求失败");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 从配置文件中获取到token
     */
    public String getTokenFromFile() {
        File file = new File(TOKEN_PATH + TOKEN_FILE_NAME);
        try {
            FileInputStream fileInputStream = new FileInputStream(file);
            byte[] bytes = new byte[300];
            int read = fileInputStream.read(bytes);
            String tokenJson = new String(bytes, 0, read);
            JSONObject jsonObject = JSONObject.parseObject(tokenJson);
            String access_token = (String) jsonObject.get("access_token");
            System.out.println("从配置文件中获取的数据  =====》 " + access_token);
            return access_token;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return "error";
        } catch (IOException e) {
            e.printStackTrace();
            return "error";
        }
    }
}
